package com.smart.community.work.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.work.entity.Attendance;
import com.smart.community.work.mapper.AttendanceMapper;
import com.smart.community.work.service.AttendanceService;
import com.smart.community.work.vo.AttendanceVO;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;

/**
 * 考勤管理服务实现类
 * 
 * 严格按照《Java后端SpringBoot代码开发规范_重构版.md》Service规范实现：
 * - 继承ServiceImpl：获得基础CRUD方法
 * - 事务管理：使用@Transactional注解管理事务
 * - 异常处理：使用统一的异常处理机制
 * - 日志记录：使用@Slf4j记录关键操作日志
 * - 参数验证：进行必要的参数验证
 * - 完整注释：所有方法都有完整的JavaDoc注释
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 * @version 1.0.0
 */
@Slf4j
@Service
public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attendance> implements AttendanceService {

    @Resource
    private AttendanceMapper attendanceMapper;

    @Override
    @Cacheable(value = "attendance", key = "'page:' + #page.current + '_' + #page.size + '_' + (#params['userId'] ?: 'null') + '_' + (#params['startDate'] ?: 'null') + '_' + (#params['endDate'] ?: 'null') + '_' + (#params['status'] ?: 'null')")
    public IPage<AttendanceVO> selectAttendancePage(Page<AttendanceVO> page, Map<String, Object> params) throws Exception {
        log.info("分页查询考勤记录，参数：{}", params);
        Long userId = (Long) params.get("userId");
        LocalDate startDate = (LocalDate) params.get("startDate");
        LocalDate endDate = (LocalDate) params.get("endDate");
        Integer status = (Integer) params.get("status");
        
        // 性能优化：使用索引字段查询，只查询必要字段
        return attendanceMapper.selectAttendancePage(page, userId, startDate, endDate, status);
    }

    @Override
    @Cacheable(value = "attendance", key = "'user:' + #userId + '_' + (#startDate ?: 'null') + '_' + (#endDate ?: 'null')")
    public List<AttendanceVO> selectByUserId(Long userId, LocalDate startDate, LocalDate endDate) throws Exception {
        log.info("根据用户ID查询考勤记录，用户ID：{}，开始日期：{}，结束日期：{}", userId, startDate, endDate);
        
        // 性能优化：使用索引字段查询，限制查询结果数量
        List<Attendance> attendanceList = attendanceMapper.selectByUserId(userId, null, startDate, endDate);
        
        // 性能优化：使用Stream并行处理（当数据量较大时）
        if (attendanceList.size() > 100) {
            return attendanceList.parallelStream()
                    .map(this::convertToVO)
                    .collect(Collectors.toList());
        } else {
            return attendanceList.stream()
                    .map(this::convertToVO)
                    .collect(Collectors.toList());
        }
    }

    @Override
    @Cacheable(value = "attendance", key = "'date:' + #attendanceDate + '_' + (#propertyCompanyId ?: 'null')")
    public List<AttendanceVO> selectByAttendanceDate(LocalDate attendanceDate, Long propertyCompanyId) throws Exception {
        log.info("根据考勤日期查询考勤记录，考勤日期：{}，物业公司ID：{}", attendanceDate, propertyCompanyId);
        List<Attendance> attendanceList = attendanceMapper.selectByAttendanceDate(attendanceDate, propertyCompanyId);
        return attendanceList.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"attendance"}, allEntries = true)
    public Boolean clockIn(Attendance attendance) throws Exception {
        log.info("员工上班打卡，用户ID：{}，考勤日期：{}", attendance.getUserId(), attendance.getAttendanceDate());
        
        // 参数验证
        if (attendance.getUserId() == null) {
            throw new BusinessException("用户ID不能为空");
        }
        if (attendance.getAttendanceDate() == null) {
            throw new BusinessException("考勤日期不能为空");
        }
        
        // 检查是否已经打卡
        LambdaQueryWrapper<Attendance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Attendance::getUserId, attendance.getUserId())
                   .eq(Attendance::getAttendanceDate, attendance.getAttendanceDate())
                   .eq(Attendance::getDeleted, 0);
        Attendance existingAttendance = this.getOne(queryWrapper);
        
        if (existingAttendance != null) {
            if (existingAttendance.getClockInTime() != null) {
                throw new BusinessException("今日已打卡，请勿重复打卡");
            }
            // 更新打卡时间
            existingAttendance.setClockInTime(LocalDateTime.now());
            existingAttendance.setLocation(attendance.getLocation());
            existingAttendance.setRemark(attendance.getRemark());
            return this.updateById(existingAttendance);
        } else {
            // 创建新的考勤记录
            attendance.setClockInTime(LocalDateTime.now());
            attendance.setStatus(1); // 1-正常
            return this.save(attendance);
        }
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"attendance"}, allEntries = true)
    public Boolean clockOut(Attendance attendance) throws Exception {
        log.info("员工下班打卡，用户ID：{}，考勤日期：{}", attendance.getUserId(), attendance.getAttendanceDate());
        
        // 参数验证
        if (attendance.getUserId() == null) {
            throw new BusinessException("用户ID不能为空");
        }
        if (attendance.getAttendanceDate() == null) {
            throw new BusinessException("考勤日期不能为空");
        }
        
        // 查找今日考勤记录
        LambdaQueryWrapper<Attendance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Attendance::getUserId, attendance.getUserId())
                   .eq(Attendance::getAttendanceDate, attendance.getAttendanceDate())
                   .eq(Attendance::getDeleted, 0);
        Attendance existingAttendance = this.getOne(queryWrapper);
        
        if (existingAttendance == null) {
            throw new BusinessException("未找到今日考勤记录，请先上班打卡");
        }
        
        if (existingAttendance.getClockOutTime() != null) {
            throw new BusinessException("今日已下班打卡，请勿重复打卡");
        }
        
        // 更新下班打卡时间
        LocalDateTime clockOutTime = LocalDateTime.now();
        existingAttendance.setClockOutTime(clockOutTime);
        
        // 计算工作时长
        if (existingAttendance.getClockInTime() != null) {
            long workMinutes = ChronoUnit.MINUTES.between(existingAttendance.getClockInTime(), clockOutTime);
            BigDecimal workHours = BigDecimal.valueOf(workMinutes).divide(BigDecimal.valueOf(60), 2, BigDecimal.ROUND_HALF_UP);
            existingAttendance.setWorkHours(workHours);
        }
        
        return this.updateById(existingAttendance);
    }

    @Override
    public Map<String, Object> getAttendanceStatistics(Long propertyCompanyId, LocalDate startDate, LocalDate endDate) throws Exception {
        log.info("统计考勤数据，物业公司ID：{}，开始日期：{}，结束日期：{}", propertyCompanyId, startDate, endDate);
        return attendanceMapper.selectAttendanceStatistics(propertyCompanyId, startDate, endDate);
    }

    @Override
    public List<Map<String, Object>> getAttendanceStatusStatistics(Long propertyCompanyId, LocalDate startDate, LocalDate endDate) throws Exception {
        log.info("统计各状态考勤数量，物业公司ID：{}，开始日期：{}，结束日期：{}", propertyCompanyId, startDate, endDate);
        return attendanceMapper.selectAttendanceStatusStatistics(propertyCompanyId, startDate, endDate);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"attendance"}, allEntries = true)
    public Boolean updateStatus(Long id, Integer status, Long updateBy) throws Exception {
        log.info("更新考勤状态，考勤ID：{}，状态：{}，更新人ID：{}", id, status, updateBy);
        
        // 参数验证
        if (id == null) {
            throw new BusinessException("考勤ID不能为空");
        }
        if (status == null) {
            throw new BusinessException("状态不能为空");
        }
        
        Integer result = attendanceMapper.updateStatus(id, status, updateBy);
        return result > 0;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"attendance"}, allEntries = true)
    public Boolean batchUpdateStatus(List<Long> ids, Integer status, Long updateBy) throws Exception {
        log.info("批量更新考勤状态，考勤ID列表：{}，状态：{}，更新人ID：{}", ids, status, updateBy);
        
        // 参数验证
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException("考勤ID列表不能为空");
        }
        if (status == null) {
            throw new BusinessException("状态不能为空");
        }
        
        // 性能优化：批量操作，避免循环单条更新
        // 分批处理，避免单次操作数据量过大
        int batchSize = 1000;
        int totalProcessed = 0;
        
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            List<Long> batchIds = ids.subList(i, endIndex);
            
            Integer result = attendanceMapper.batchUpdateStatus(batchIds, status, updateBy);
            totalProcessed += result;
        }
        
        return totalProcessed > 0;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"attendance"}, allEntries = true)
    public Boolean deleteById(Long id, Long updateBy) throws Exception {
        log.info("删除考勤记录，考勤ID：{}，更新人ID：{}", id, updateBy);
        
        // 参数验证
        if (id == null) {
            throw new BusinessException("考勤ID不能为空");
        }
        
        Integer result = attendanceMapper.deleteById(id, updateBy);
        return result > 0;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"attendance"}, allEntries = true)
    public Boolean batchDelete(List<Long> ids, Long updateBy) throws Exception {
        log.info("批量删除考勤记录，考勤ID列表：{}，更新人ID：{}", ids, updateBy);
        
        // 参数验证
        if (ids == null || ids.isEmpty()) {
            throw new BusinessException("考勤ID列表不能为空");
        }
        
        // 性能优化：批量操作，避免循环单条删除
        // 分批处理，避免单次操作数据量过大
        int batchSize = 1000;
        int totalProcessed = 0;
        
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            List<Long> batchIds = ids.subList(i, endIndex);
            
            Integer result = attendanceMapper.batchDelete(batchIds, updateBy);
            totalProcessed += result;
        }
        
        return totalProcessed > 0;
    }

    /**
     * 转换Entity为VO
     * 
     * @param attendance 考勤记录实体
     * @return 考勤记录VO
     */
    private AttendanceVO convertToVO(Attendance attendance) {
        if (attendance == null) {
            return null;
        }
        AttendanceVO vo = new AttendanceVO();
        BeanUtils.copyProperties(attendance, vo);
        return vo;
    }
}